package io.wongxd.solution.foregroundService

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.graphics.Color
import android.os.Binder
import android.os.Build
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.lifecycle.LifecycleService
import io.wongxd.solution.R
import java.lang.ref.WeakReference

class ForegroundServiceHelper {
}

// <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>


//class MainActivity : AppCompatActivity() {
//
//    override fun onCreate(savedInstanceState: Bundle?) {
//        super.onCreate(savedInstanceState)
//        setContentView(R.layout.activity_main)
//
//        //如果大于8.0需要设计好Notification的显示内容
//        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
//        //这是Notification点击跳转使用的PendingIntent,如果想直接移除前台通知,下面的pendingIntent参数可给null
//            val pendingIntent = Intent(this, MainActivity::class.java).apply {
//                flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
//            }
//            //创建一个前台通知的Notification对象
//            val foregroundNotification = Notify.foregroundNotification(
//                this,
//                "我是通知的内容",
//                pendingIntent,
//                R.string.notification_title  //通知的标题
//            )
//            //先设置好Notification和NotificationId
//            StoreClient.getInstance().setForegroundService(foregroundNotification, 100)
//        }
//        //再开启服务
//        StoreClient.getInstance().bindService(this)
//    }
//
//    override fun onDestroy() {
//        super.onDestroy()
//        //解绑服务
//        StoreClient.getInstance().unbindService(this)
//    }
//}

/**
 * StoreControlService的客户端管理类，可以调用Service所有的方法。不能直接使用Service对象。
 */
class StoreClient {
    private var controlService: StoreControlService? = null   //service对象,用于调用service的方法
    private val serviceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName, binder: IBinder) {
            if (StoreServiceBinder::class.java.isAssignableFrom(binder.javaClass)) {
                //获取Service对象
                controlService = (binder as StoreServiceBinder).getService()?.get()
                serviceBound = true
            }
        }

        override fun onServiceDisconnected(name: ComponentName) {
        }
    }
    private lateinit var mServiceStartIntent: Intent

    // notification for Foreground Service
    private var foregroundServiceNotification: Notification? = null  //前台服务的通知
    private var foregroundServiceNotificationId = -1   //前台服务的通知的Id

    @Volatile
    private var serviceBound = false   //service是否绑定

    /**
     * 单例模式
     */
    companion object {
        private val SERVICE_NAME = StoreControlService::class.java.name
        private var instance: StoreClient? = null

        @Synchronized
        fun getInstance(): StoreClient {    //单例
            if (instance == null) {
                instance = StoreClient()
            }
            return instance!!
        }
    }

    /**
     * 如果是>= Build.VERSION_CODES.O ,则需要设置前台服务
     * 通知Notification的内容需要自定义
     */
    fun setForegroundService(notification: Notification, id: Int) {
        foregroundServiceNotification = notification
        foregroundServiceNotificationId = id
    }

    /**
     * 绑定服务
     */
    fun bindService(context: Context) {
        mServiceStartIntent = Intent().apply {
            setClassName(context, SERVICE_NAME)
        }
        var service: Any? = null
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && foregroundServiceNotification != null) {
            Log.d("TAG", "startForegroundService")
            //将Notification放入Intent,在Service的onStartCommand方法中获取
            mServiceStartIntent.putExtra(
                StoreControlService.FOREGROUND_SERVICE_NOTIFICATION,
                foregroundServiceNotification
            )
            //将NotificationId放入Intent,在Service的onStartCommand方法中获取
            mServiceStartIntent.putExtra(
                StoreControlService.FOREGROUND_SERVICE_NOTIFICATION_ID,
                foregroundServiceNotificationId
            )
            //开启前台服务并传递Intent
            service = context.startForegroundService(mServiceStartIntent)
        } else {
            Log.d("TAG", "startService")
            try {
                //开启普通服务并传递Intent
                service = context.startService(mServiceStartIntent)
            } catch (ex: IllegalStateException) {

            }
        }
        if (service == null) {
            throw RuntimeException("cannot start service $SERVICE_NAME")
        }
        Log.d("TAG", "bindService")
        //绑定服务,采用混合开启的方式
        context.bindService(mServiceStartIntent, serviceConnection, Context.BIND_AUTO_CREATE)
    }


    /**
     * 解绑服务
     */
    fun unbindService(context: Context) {
        if (serviceBound) {  //如果有绑定
            try {
                context.unbindService(serviceConnection)   //解绑
                context.stopService(mServiceStartIntent)   //停止服务
                serviceBound = false
            } catch (e: IllegalArgumentException) {
            }
        }
    }

    /**
     * 上传文件的方法供外部调用,具体实现逻辑在Service中
     */
    fun uploadFile() {
        controlService?.uploadFile()
    }

    /**
     * 下载文件的方法供外部调用,具体实现逻辑在Service中
     */
    fun downloadFile() {
        controlService?.downloadFile()
    }

}

internal interface StoreConstants {
    companion object {
        const val CALLBACK_ACTIVITY_TOKEN = "activityToken"
    }
}

//弱引用，不然会有内存泄漏
class StoreServiceBinder() : Binder() {
    var binderToken: String? = null
    private var weakReferenceService: WeakReference<StoreControlService>? = null

    constructor(service: StoreControlService) : this() {
        weakReferenceService = WeakReference(service)
    }

    fun getService(): WeakReference<StoreControlService>? = weakReferenceService
}

class StoreControlService : LifecycleService() {

    private var storeServiceBinder: StoreServiceBinder? = null

    companion object {
        val FOREGROUND_SERVICE_NOTIFICATION_ID =
            StoreControlService::class.java.simpleName + ".FOREGROUND_SERVICE_NOTIFICATION_ID"
        val FOREGROUND_SERVICE_NOTIFICATION =
            StoreControlService::class.java.simpleName + ".FOREGROUND_SERVICE_NOTIFICATION"
    }

    override fun onCreate() {
        super.onCreate()
        storeServiceBinder = StoreServiceBinder(this)
    }

    override fun onBind(intent: Intent): IBinder? {
        super.onBind(intent)
        storeServiceBinder?.binderToken =
            intent.getStringExtra(StoreConstants.CALLBACK_ACTIVITY_TOKEN)
        return storeServiceBinder
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        super.onStartCommand(intent, flags, startId)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //通过Intent获取创建好的Notification
            val foregroundServiceNotification =
                intent?.getParcelableExtra<Notification>(FOREGROUND_SERVICE_NOTIFICATION)
            if (foregroundServiceNotification != null) {
                //开启前台通知
                startForeground(
                    intent.getIntExtra(FOREGROUND_SERVICE_NOTIFICATION_ID, 1),
                    foregroundServiceNotification
                )
                //直接移除前台通知,也可以给Notification设置PendingIntent点击实现跳转
                stopForeground(true)
            }
        }
        return START_STICKY
    }

    /**
     * 上传文件
     */
    fun uploadFile() {
        //具体实现逻辑代码略...
    }

    /**
     * 下载文件
     */
    fun downloadFile() {
        //具体实现逻辑代码略...
    }

    override fun onDestroy() {
        if (storeServiceBinder != null) {
            storeServiceBinder = null
        }
        super.onDestroy()
    }

}

//通知工具类
internal object Notify {

    private var MessageID = 100
    private const val channelId = "chn-01"
    private const val channelFireBaseMsg = "Chn Store"

    private val pendingIntentFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
    } else {
        PendingIntent.FLAG_UPDATE_CURRENT
    }

    //发通知
    fun notification(
        context: Context,
        icon: Int = R.drawable.w_solution_star_bar_star,
        messageString: String,
        intent: Intent?,
        notificationTitle: Int
    ) {

        //Get the notification manage which we will use to display the notification
        val ns = Context.NOTIFICATION_SERVICE
        val notificationManager = context.getSystemService(ns) as NotificationManager

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val notificationChannel = NotificationChannel(
                channelId,
                channelFireBaseMsg,
                NotificationManager.IMPORTANCE_LOW
            )
            notificationChannel.enableLights(true)
            notificationChannel.lightColor = Color.RED
            notificationChannel.enableVibration(true)
            notificationChannel.vibrationPattern =
                longArrayOf(100, 200, 300, 400, 500, 400, 300, 200, 400)

            notificationManager.createNotificationChannel(notificationChannel)
        }

        val `when` = System.currentTimeMillis()

        //get the notification title from the application's strings.xml file
        val contentTitle: CharSequence = context.getString(notificationTitle)

        //the message that will be displayed as the ticker
        val ticker = "$contentTitle $messageString"

        //build the pending intent that will start the appropriate activity
        val pendingIntent = PendingIntent.getActivity(context, 0, intent, pendingIntentFlags)

        //build the notification
        val notificationCompat = NotificationCompat.Builder(context, channelId)
        notificationCompat.setAutoCancel(true)
            .setContentTitle(contentTitle)
            .setContentIntent(pendingIntent)
            .setContentText(messageString)
            .setTicker(ticker)
            .setWhen(`when`)
            .setSmallIcon(icon)
        val notification = notificationCompat.build()

        notificationManager.notify(MessageID, notification)
        MessageID++
    }

    //创建前台通知对象
    fun foregroundNotification(
        context: Context,
        icon: Int = R.drawable.w_solution_star_bar_star,
        connectionName: String,
        intent: Intent?,
        notificationTitle: Int
    ): Notification {
        //Get the notification manage which we will use to display the notification
        val ns = Context.NOTIFICATION_SERVICE
        val notificationManager = context.getSystemService(ns) as NotificationManager

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val notificationChannel = NotificationChannel(
                channelId,
                channelFireBaseMsg,
                NotificationManager.IMPORTANCE_LOW
            )
            notificationChannel.enableLights(true)
            notificationChannel.lightColor = Color.RED
            notificationChannel.enableVibration(true)
            notificationChannel.vibrationPattern =
                longArrayOf(100, 200, 300, 400, 500, 400, 300, 200, 400)

            notificationManager.createNotificationChannel(notificationChannel)
        }

        val `when` = System.currentTimeMillis()

        //get the notification title from the application's strings.xml file
        val contentTitle: CharSequence = context.getString(notificationTitle)

        //the message that will be displayed as the ticker
        val ticker = "$contentTitle $connectionName"

        //build the pending intent that will start the appropriate activity
        val pendingIntent =
            PendingIntent.getActivity(context, 0, intent ?: Intent(), pendingIntentFlags)

        //build the notification
        val notificationCompat = NotificationCompat.Builder(context, channelId)
        notificationCompat
            .setAutoCancel(true)
            .setContentTitle(contentTitle)
            .setContentIntent(pendingIntent)
            .setContentText(connectionName)
            .setTicker(ticker)
            .setWhen(`when`)
            .setSmallIcon(icon)
        return notificationCompat.build()
    }
}


